var $ = window.$;
var frac = require('../../../util/frac');
var Log = require('../../../util/logger');
var path = require('path');
var util = require('../../../util/index');
var notify = require('../../notify/ui');
var grid = require('../../grid/manager');
var io = require('../../io/ui');
var config = require('../../../core/config');


var ret = {
    CH_MAP : [16, 11, 12, 13, 14, 15, 18, 19], //0-7按键到实际通道的映射

    exportBms : function(chart){
        var output = [];
        var hexIdx, i, note, measure, k, grp;
        var self = this;

        // meta数据
        output.push("*---------------------- HEADER FIELD");
        output.push("#PLAYER 1");
        output.push("#TITLE " + chart.meta.song.title);
        output.push("#ARTIST " + chart.meta.song.artist);
        output.push("#BPM " + chart.time[0].bpm);
        output.push("#DIFFICULTY " + this.estimateDifficulty(chart));
        output.push("#LNTYPE 1");
        output.push("");

        // 拷贝一份note 后面要修改note序列
        var tmpNotes = $.extend([], chart.note);

        // 对音频进行编号
        var sndIndex = 1;
        var soundMap = {};
        for(i=0;i<tmpNotes.length;i++){
            note = tmpNotes[i];
            note.beat = frac.reduce(note.beat);
            if(note.endbeat){
                note.endbeat = frac.reduce(note.endbeat);
            }
            if(!note.sound){
            	// 没KEY音使用ZZ占位
           		note.chStr = "ZZ";
                continue;
            }
            hexIdx = soundMap[note.sound];
            if(!hexIdx){
                hexIdx = this.dec2Hex(sndIndex);
                if(hexIdx === null){
                    continue;
                }
                soundMap[note.sound] = hexIdx;
                sndIndex ++;
                output.push("#WAV" + hexIdx  + " " + note.sound);
            }
            note.chStr = hexIdx;
            // 纯key音映射到01
            if(chart.extra.toggle[note.column] == 2){
                note.channel = "01";
            }
        }
        output.push("");

        // 根据方式1处理长音 把长音的终止符拆成单独的note
        for(i=0;i<chart.note.length;i++){
            note = chart.note[i];
            if(note.endbeat){
            	note.isLN = true;
                tmpNotes.push({
                    beat : note.endbeat,
                    column : note.column,
                    chStr : note.chStr,
                    isLN : true
                });
            }
        }

        // 对bpm进行编号 但是如果歌曲不变速这步可以略过
        var multiBpm = chart.time.length > 1;
        if(multiBpm){
            for(i=0;i<chart.time.length;i++){
                hexIdx = this.dec2Hex(i+1);
                output.push("#BPM" + hexIdx + " " + chart.time[i].bpm);
                // 将bpm速度数据合并到note中 保证总体控制数据的递增排序
                tmpNotes.push({
                    beat : chart.time[i].beat,
                    bpm : chart.time[i].bpm,
                    channel : "08",
                    chStr : hexIdx
                });
            }
            output.push("");
        }

        // 重新排序
        tmpNotes.sort(function(a, b){
            return grid.compareNote(a,b);
        });

        // 重新映射note的channel
        this.remapColumns(chart, tmpNotes);

        // 把note按小节分组
        var groupNotes = [];
        for(i=0;i<tmpNotes.length;i++){
        	note = tmpNotes[i];
        	measure = Math.floor(note.beat[0] / 4);
        	grp  = groupNotes[measure];
        	if(!grp){
        		grp = [];
        	}
        	grp.push(note);
        	groupNotes[measure] = grp;
        }

        var channels;
        output.push("*---------------------- MAIN DATA FIELD");
        for(k in groupNotes){
        	grp = groupNotes[k];
        	if(!k){
        		continue;
        	}
        	//按channel分组 第一个是bgm 第二个是变速 后面的转盘和1-7轨道  长音
            channels = {
                "01" : [], "08" : [], "16" : [], "11" : [], "12" : [], "13" : [], "14" : [],
                "15" : [], "18" : [], "19" : [], "56" : [], "51" : [], "52" : [], "53" : [],
                "54" : [], "55" : [], "58" : [], "59" : []
            };
        	for(i=0;i<grp.length;i++){
        		note = grp[i];
        		if(note.channel){
                	channels[note.channel].push(note);
                }
        	}
            this.outputChannel(channels, +k, output);
        }

        return output.join("\n");
    },

    outputChannel : function(channels, measure, output){
        var channelNotes, i, lcm, blankArr, note, j, pos, chStr, tmpArr;
        for(var i in channels){
            channelNotes = channels[i];
            if(!channelNotes.length){
                continue;
            }
            //一个频道如果有音符重复（比如bgm轨）就要输出几次
            while(channelNotes.length){
                lcm = this.calcDivideLCM(channelNotes); //当前小节被等分的刻度数实际上是4*lcm 因为一组是4个beat
                blankArr = this.getBlankArr(lcm * 4);
                tmpArr = [];
                for(j=0;j<channelNotes.length;j++){
                    note = channelNotes[j];
                    pos = (note.beat[0] % 4) * lcm + lcm / note.beat[2] * note.beat[1];
                    if(pos >= blankArr.length){
                        continue;
                    }
                    if(blankArr[pos] == "00"){
                        blankArr[pos] = note.chStr;
                    }else{
                        tmpArr.push(note);
                        continue;
                    }
                    delete note.channel;
                    delete note.chStr;
                }
                chStr = this.padZero(measure,3) + i;
                blankArr = this.reduceArr(blankArr);
                output.push("#" + chStr + ":" + blankArr.join(""));
                channelNotes = tmpArr;
            }
        }
    },

    estimateDifficulty : function(chart){
        var beatCnt = chart.note[chart.note.length - 1].beat[0];
        var len = 36000 / chart.time[chart.time.length - 1].bpm / 1000;
        var nDensity = chart.note.length /  (beatCnt * len);
        var diff = Math.ceil(nDensity / 10);
        diff = diff > 5 ? 5 : diff;
        return diff;
    },

    padZero : function (num, n) {
        num = "" + num ;
        var pad = n > num.length ? new Array(n - num.length + 1).join(0) : "";
        return pad+num;
    },

    calcDivideLCM : function(notes){
        var arr = [];
        var tmp;
		for(var i=0;i<notes.length;i++){
            arr.push(notes[i].beat[2]);
        }
        while(arr.length > 1){
            tmp = [];
            for(var j=0;j<Math.floor(arr.length/2);j++){
                tmp.push(this.lcm(arr[j*2], arr[j*2+1]));
            }
            if(arr.length%2){
                tmp.push(arr[arr.length-1]);
            }
            arr = tmp;
        }
        return arr[0];
    },

    lcm : function(a, b){
        return a * b / frac.gcd(a, b);
    },

    /**
     * 获得一组00填充的矩阵 用于放流数据
     * @param size
     */
    getBlankArr : function(size){
        var ret = new Array(size);
        for(var i=0;i<size;i++){
            ret[i] = "00";
        }
        return ret;
    },

    reduceArr : function(arr){
        if(arr.length != 4){
            return arr;
        }
        if(arr[1] == "00" && arr[2] == "00" && arr[3] == "00"){
            return [arr[0]];
        }else if(arr[1] == "00" && arr[3] == "00"){
            return [arr[0], arr[2]];
        }else{
            return arr;
        }
    },

    remapColumns : function(chart, tmpNotes){
        var noteColumn = [];
        var mapping = {100 : 9};
        var toggle = chart.extra.toggle;
        for(var i=0;i<toggle.length;i++){
            if(toggle[i] == 1){
                noteColumn.push(i); //非play轨的声音全映射到0轨去
            }
        }
		for(var i=0;i<noteColumn.length;i++){
			mapping[noteColumn[i]] = i;
		}
        for(var i=0;i<tmpNotes.length;i++){
            var note = tmpNotes[i];
            if(!note.channel){
                note.channel = this.CH_MAP[mapping[note.column]];
                if(note.isLN){
                	note.channel += 40;
                	delete(note.isLN);
                }
                note.channel = note.channel + "";
            }
        }
    },

    dec2Hex : function(num){
        num = +num;
        if(num>1295){
            //最多只支持36^2 - 1的数字编码
            return null;
        }
        if(num === 0){
            return "00";
        }
        var result = [];
        var a;
        while(num){
            a = num % 36;
            num = Math.floor(num / 36);
            if(a<10){
                result.push(a);
            }else{
                result.push(String.fromCharCode(65 + a - 10));
            }
        }
        var output = result.reverse().join("")
        //如果不足两位 要补足两位
        if(result.length == 1){
            output = "0" + output;
        }
        return output;
    }
};

module.exports = ret;